@file:OptIn(ExperimentalForeignApi::class)

package com.tencent.compose.utils

import androidx.compose.ui.napi.JsEnv
import kotlinx.cinterop.ExperimentalForeignApi
import platform.ohos.napi_value

data class FooObject(
    val id: String,
    val strValue: String = "test0911",
    val boolValue: Boolean = false,
    val intValue: Int = 0,
    val longValue: Long = 0,
    val doubleValue: Double = 0.0,
    val cache: Array<FooObject> = arrayOf(),
    val fooValue: FooObject? = null  // 使用可空类型避免无限递归
)

fun JsEnv.setNamedProperty(obj: napi_value?, key: String, value: napi_value?) {
    JsEnv.setProperty(obj, JsEnv.createStringUtf8(key), value)
}

fun TsEnv.setNamedProperty(obj: napi_value?, key: String, value: napi_value?) {
    TsEnv.setProperty(obj, TsEnv.createStringUtf8(key), value)
}

object JsFoo {
    fun toNapiValue(foo: FooObject?): napi_value? {
        if (foo == null) return null
        val obj = JsEnv.createObject() ?: return null
        JsEnv.setNamedProperty(obj, "id", JsEnv.createStringUtf8(foo.id))
        JsEnv.setNamedProperty(obj, "strValue", JsEnv.createStringUtf8(foo.strValue))
        JsEnv.setNamedProperty(obj, "boolValue", JsEnv.getBoolean(foo.boolValue))
        JsEnv.setNamedProperty(obj, "intValue", JsEnv.createInt32(foo.intValue))
        JsEnv.setNamedProperty(obj, "longValue", JsEnv.createInt64(foo.longValue))
        JsEnv.setNamedProperty(obj, "doubleValue", JsEnv.createDouble(foo.doubleValue))
        JsEnv.setNamedProperty(obj, "cache", JsEnv.createDouble(foo.doubleValue))
        if (foo.fooValue != null) {
            JsEnv.setNamedProperty(obj, "fooValue", toNapiValue(foo.fooValue))
        } else {
            JsEnv.setNamedProperty(obj, "fooValue", null)
        }
        return obj
    }

    fun toFooObject(value: napi_value?): FooObject? {
        if (value == null) return null
        val id =
            JsEnv.getNamedProperty(value, "id")?.let { JsEnv.getValueStringUtf8(it) } ?: return null
        val strValue =
            JsEnv.getNamedProperty(value, "strValue")?.let { JsEnv.getValueStringUtf8(it) } ?: ""
        val boolValue =
            JsEnv.getNamedProperty(value, "boolValue")?.let { JsEnv.getValueBool(it) } ?: false
        val intValue =
            JsEnv.getNamedProperty(value, "intValue")?.let { JsEnv.getValueInt32(it) } ?: 0
        val longValue =
            JsEnv.getNamedProperty(value, "longValue")?.let { JsEnv.getValueInt64(it) } ?: 0L
        val doubleValue =
            JsEnv.getNamedProperty(value, "doubleValue")?.let { JsEnv.getValueDouble(it) } ?: 0.0
        val fooValue = JsEnv.getNamedProperty(value, "fooValue")?.let { toFooObject(it) }
        return FooObject(id, strValue, boolValue, intValue, longValue, doubleValue, arrayOf(), fooValue)
    }
}

object TsFoo {
    fun toNapiValue(foo: FooObject?): napi_value? {
        if (foo == null) return null
        val obj = TsEnv.createObject() ?: return null
        TsEnv.setNamedProperty(obj, "id", TsEnv.createStringUtf8(foo.id))
        TsEnv.setNamedProperty(obj, "strValue", TsEnv.createStringUtf8(foo.strValue))
        TsEnv.setNamedProperty(obj, "boolValue", TsEnv.getBoolean(foo.boolValue))
        TsEnv.setNamedProperty(obj, "intValue", TsEnv.createInt32(foo.intValue))
        TsEnv.setNamedProperty(obj, "longValue", TsEnv.createInt64(foo.longValue))
        TsEnv.setNamedProperty(obj, "doubleValue", TsEnv.createDouble(foo.doubleValue))
        if (foo.fooValue != null) {
            TsEnv.setNamedProperty(obj, "fooValue", toNapiValue(foo.fooValue))
        } else {
            TsEnv.setNamedProperty(obj, "fooValue", null)
        }
        return obj
    }

    fun toFooObject(value: napi_value?): FooObject? {
        if (value == null) return null
        val id =
            TsEnv.getNamedProperty(value, "id")?.let { TsEnv.getValueStringUtf8(it) } ?: return null
        val strValue =
            TsEnv.getNamedProperty(value, "strValue")?.let { TsEnv.getValueStringUtf8(it) } ?: ""
        val boolValue =
            TsEnv.getNamedProperty(value, "boolValue")?.let { TsEnv.getValueBool(it) } ?: false
        val intValue =
            TsEnv.getNamedProperty(value, "intValue")?.let { TsEnv.getValueInt32(it) } ?: 0
        val longValue =
            TsEnv.getNamedProperty(value, "longValue")?.let { TsEnv.getValueInt64(it) } ?: 0L
        val doubleValue =
            TsEnv.getNamedProperty(value, "doubleValue")?.let { TsEnv.getValueDouble(it) } ?: 0.0
        val fooValue = TsEnv.getNamedProperty(value, "fooValue")?.let { toFooObject(it) }
        return FooObject(id, strValue, boolValue, intValue, longValue, doubleValue, arrayOf(),fooValue)
    }
}
